/** \file NewHandler.cc
 * Definitions for the class NewHandler.
 *
 * (c) Copyright  Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * $Id: NewHandler.cc 119 2006-06-21 04:57:25Z semihc $
 *
 *
 */


#include "NewHandler.hh"
//include <iostream>

using namespace std;
using namespace TC;


TC_IDENT("$Id$");


NewHandler* NewHandler::s_Instance = 0;

NewHandler* NewHandler::Instance()
{
  if(!s_Instance) {
    s_Instance = new NewHandler;
  }
  
  return s_Instance;
}


// Deallocate the singleton instance
void NewHandler::DeleteInstance()
{
  delete s_Instance;
  s_Instance = 0;
}


NewHandler::NewHandler() :
  m_rsize(0), m_reserve(0), m_oldhandler(0)
{
}


NewHandler::~NewHandler()
{
  releaseReserve();
  uninstallHandler();
}


int NewHandler::allocateReserve(int desiredSize)
{
  releaseReserve();

  while(m_reserve==0 && desiredSize>0) {
    try {
      m_reserve = new char[desiredSize];
      m_rsize = desiredSize;
    }
    catch(const std::bad_alloc&) {
      desiredSize /= 2; 
    }
  } // end while
  

  return desiredSize;
}


void NewHandler::releaseReserve()
{
  if(m_rsize) {
    delete[] m_reserve;
    m_rsize = 0;
    m_reserve = 0;
  }
}


new_handler NewHandler::installHandler(new_handler hlr)
{
  m_oldhandler = set_new_handler(hlr);
  return m_oldhandler;
}


void NewHandler::uninstallHandler()
{
  set_new_handler(m_oldhandler);
}



//! Substitute for the default new handler
void TC::Global_new_handler()
{
  static bool nested = false;

  if(nested) {
    // We recursed into the handler, don't try to do anything
    throw std::bad_alloc();
  }
  
  nested = true;
  NewHandler* n = NewHandler::Instance();
  if(n->getReserveSize() > 0) {
    n->releaseReserve();
    nested = false;
    return;
  }

  //TODO: Should we log this?
  nested = false;
  throw std::bad_alloc();
}
